/**
 * 
 */
package net.looker.work;

import java.util.logging.Level;
import java.util.logging.Logger;

import net.looker.util.BlockQueue;

/**
 * 工作线程
 * 此为真正的工作者，有独立的线程。工作者就是执行工作的
 * 工作是一个接口，定义的一个启动函数，startWork()工作者接受到工作时就启动工作接口定义的startWork()方法.
 * 工作线程完成了工作之后就返回到空闲的工作者的队列中，等待下一次工作的分配
 * @author solosky
 *
 */
public class Worker
{
	/**
	 * 下一工作者的ＩＤ
	 */
	private static int nextWorkerID;
	
	/**
	 * 日志记录器
	 */
	private static Logger logger;
	
	/**
	 * 此线程的工作者ＩＤ
	 */
	private int workerID;
	
	/**
	 * 工作队列，只能容纳一个工作，因为一个线程只能同时完成一个工作
	 * 如果工作队列为空就等待，直到有工作可做
	 */
	private BlockQueue<Work> workQueue;
	
	/**
	 * 内部运行线程
	 * 主要工作都是让这个线程来启动，自运行线程
	 */
	private Thread innerThread;
	
	/**
	 * 停止工作标志
	 * 用于停止工作者的工作
	 */
	private volatile boolean stop;
	
	/**
	 * 空闲的工作者队列
	 * 用于当工作者没工作的时候，将自己添加到空闲的工作者队列里，等待分配工作
	 */
	private BlockQueue<Worker> idleWorkerQueue;
	
	/**
	 * 构造函数
	 * 
	 */
	public Worker(BlockQueue<Worker> idleWorkers)
	{
		//日志记录对象
		if (logger==null) logger = Logger.getLogger("looker");
		//分配工作ＩＤ
		workerID  = Worker.getNextWorkerID();
		//建立只有一个容量的工作队列
		workQueue = new BlockQueue<Work>(1);
		//设置停止标志为假
		stop      = false;
		//保存空闲工作者队列的引用
		idleWorkerQueue = idleWorkers;
		
		//创建自运行对象，用于工作
		Runnable r =  new Runnable ()
		{
			public void run()
			{
				try{
					//开始工作，刚开始时，没有工作，会在runWork等待，直到有工作可做
					runWork();
				}catch (Throwable ex){
					//阻止任何错误导致线程的终止
					ex.printStackTrace();
				}
			}//end run..
		};//end Runnable..
		
		//建立内部线程，并启动
		innerThread = new Thread(r);
		innerThread.start();
	}
	
	/**
	 * 开始工作
	 * 这里用了一个无限的循环来反复地执行工作，直到设置了停止工作标志，然后函数优美的结束自己的线程
	 */
	private void runWork()
	{
		//反复执行工作，直到要求停止工作
		
		try{
			while ( !stop )
			{
				//工作线程准备工作
				//因为空闲工作者队列具有保存所有工作者线程的容量，所以永远不会阻塞在添加自己到空闲工作者队列中
				idleWorkerQueue.add(this);
				//logger.fine("worker:"+workerID+" wait for work...");

				//在此等待工作，一直到工作池给了工作
				Work work = workQueue.remove();
				
				logger.fine("线程"+workerID+"开始工作");
				//开始工作
				startWork(work);
			}
		}catch( InterruptedException ex){
			//再声明异常
			Thread.currentThread().interrupt();
			//logger.info("工作线程"+workerID+"已经中断...");
		}
	}
	
	/**
	 * 启动线程，开始工作
	 */
	private void startWork(Work work)
	{
		try{
			work.startWork();
		} catch(Exception ex){
			//捕获所有的异常，防止线程终止
			logger.log(Level.WARNING, "工作线程出现异常", ex);
			ex.printStackTrace();	
		}finally {
			//清除中断标志，如果再次经过循环，workQueue.remove()不会抛出InterruptedException...不是很懂。。。
			Thread.interrupted();
		}
	}
	
	/**
	 * 给工作者分配工作
	 * @param Work
	 * @throws InterruptedException 
	 */
	public void assignWork(Work work) throws InterruptedException
	{
		 // 一旦workQueue队列添加了工作，等待的线程runWork()就会注意到工作来了，并开始工作
		//注意runWork()是在内部线程中，而assignWork()是在外部线程中
		workQueue.add(work);
	}
	
	/**
	 * 结束工作者的工作
	 */
	public void stopWork()
	{
		//stop 是 valatie 类型的变量，外部类值的改变立刻反应到内含类中，即可运行对象
		stop = true;
		//中断工作者的线程
		innerThread.interrupt();
	}
	
	/**
	 * 得到工作者的ＩＤ
	 *  @return int id
	 */
	public static synchronized int getNextWorkerID()
	{
		return nextWorkerID++;
	}
}
